骆小刚:Linux后台服务启动方式systemd、daemon、nohup大比拼
作者简介
骆小刚,现就职于深圳市普康电子有限公司,高级软件工程师。负责arm下u-boot、kernel开发,APP框架搭建,底层软件开发,算法开发,性能优化等。对开源软件有浓厚兴趣。
本文主要用实例剖析systemd、daemon()、nohup启动服务的差异。
环境:ubuntu 1804 x86_64, linux 5.0, gcc 8.3.0
1. systemd启动服务
systemd是最新linux发行版管理后台的服务的默认形式,用以取代原有的init。
1.1 编写服务程序
vim simple-server.c
gcc simple-server.c -o simple-server
1.2 配置服务
编辑服务配置文件simple-server.service
vim simple-server.service
解析:
[Unit] :服务单元
Description:对该服务进行简单的描述
[Service]:服务运行时行为配置
ExecStart:程序的完整路径
Restart:重启配置,no、always、on-success、on-failure、on-abnormal、on-abort、on-watchdog
[Install]:安装配置
WantedBy:多用户等
其他配置选项请参考:
https://www.freedesktop.org/software/systemd/man/systemd.service.html
将配置拷贝到/lib/systemd/system/目录下:
sudo cp simple-server.service /lib/systemd/system/
1.3 启用服务
sudo systemctl enable simple-server
会创建一个指向配置文件/lib/systemd/system/simple-server.service的符号链接
/etc/systemd/system/multi-user.target.wants/simple-server.service
1.4 开启服务
sudo systemctl start simple-server
1.5 服务状态
1.5.1服务与终端的关系
pstree
可以看到systemd启动的服务直接是pid=1的systemd进程的子进程。
可以看到服务程序忽略了SIGPIPE信号。
服务没有控制终端(tty为“?”)。
1.5.3 服务的运行日志
sudo lsof -p 6213
用lsof可以看到服务的用户为root,当前目录和根目录都是“/”,输入被重定向到/dev/null,输出和出错被重定向到socket。
1.5.4 服务的运行状态
sudo systemctl status simple-server
我可以看到simple-server服务已经loaded,并且处于active状态。还可以看到PID、Tasks数量、服务管理日志等。
1.6 关闭服务
sudo systemctl stop simple-server
1.7 停用服务
sudo systemctl disable simple-server
2. daemon启动服务
2.1 编写代码
vim daemon.c
gcc daemon.c -o daemon
2.2 启动服务
./daemon
2.3 服务状态
2.3.1 服务与终端的关系
服务把自己设置为会话首领,父进程是当前用户级的systemd(subreaper ),完全脱离终端。
2.3.2 服务的信号处理
ps -C daemon s
没有屏蔽信号。
控制终端tty为“?”
2.3.3 服务的运行日志
当前目录和根目录都是“/”,用户为普通用户,输入、输出、出错都重定向到/dev/null
2.4 停止服务
killall daemon
3. nohup 启动服务
3.1 编写代码
vim nohup.c
gcc nohup.c -o nohup
3.2 启动服务
用nohup命令启动这个名字也叫nohup的程序
(注意后面一个nohup是上面写的那个很简单的程序的名字)
nohup ./nohup
3.3 服务状态
3.3.1服务与终端的关系
服务的父进程是启动该服务的bash,和bash在一个会话组。
3.3.2 服务的信号处理
普通用户,屏蔽SIGHUP信号,依赖终端bash。由于屏蔽了SIGHUP,终端关闭的时候,会忽略终端发送的SIGHUP信号,继续运行服务。
3.3.3服务的运行日志
输入被重定向到/dev/null,输出、出错为当前目录下的nohup.out,格式没有带时间,不便于分析问题。
3.4 服务关闭
killall nohup
4. 总结
4.1 后台运行服务的基本需求
基本需求:
脱离终端(终端关闭时,服务不能关闭)
处理输入、输出、出错描述符
4.1.1 systemd
自己本身就是一个init或者user级的subreaper;
系统级systemd启动的服务以root权限运行;
重定向输入到/dev/null,输出、出错通过socket发给系统日志模块。
4.1.2 daemon
通过fork后父进程exit,让子进程托孤给subreaper,实现在后台运行服务。
重定向输入、输出、出错到/dev/null.
源码参考:
https://github.com/lattera/glibc/blob/master/misc/daemon.c
4.1.3 nohup
通过忽略终端关闭时的广播信号SIGHUP,实现在后台运行服务。
重定向输入到/dev/null,输出、出错重定向到当前目录下的nohup.out文件,
4.2 后台运行服务的高级需求
高级需求:
方便分析问题的服务运行日志记录
服务管理的日志
异常退出时可以根据需要重新启动
daemon不能实现上面的高级需求。
nohup 只能记录服务运行时的输出和出错日志。
只有systemd能够实现上述所有需求。
默认的日志中增加了时间、用户名、服务名称、PID等,非常人性化。
还能看到服务运行异常退出的日志。
还能通过/lib/systemd/system/下的配置文件定制各种需求。
还有非常非常多强大的功能等着你去探索:
https://www.freedesktop.org/software/systemd/man/systemd.html
4.3 systemd是目前linux管理后台服务的主流方式
点一点右下角”在看”,为阅码场打Call~